/**
 * 
 */
package com.wilmar.process.dao.impl;

import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.wilmar.common.util.PageinationEntity;
import com.wilmar.process.dao.api.IBaseDAO;
import com.wilmar.process.enumerate.EnumSystemQueryNameSet;

/**
 * 范型 DAO
 * 
 * @author MaKuBEX E-mail:makubexnet@gmail.com
 * @version 1.0.0 at Jul 3, 2009 5:10:10 PM
 * 
 */
public abstract class BaseDAOImpl<T, PK extends java.io.Serializable> extends
		HibernateDaoSupport implements IBaseDAO<T, PK> {

	private static final Logger log = Logger.getLogger(BaseDAOImpl.class);

	private Class<T> tClass;

	@SuppressWarnings("unchecked")
	public BaseDAOImpl() {
		this.tClass = (Class<T>) ((ParameterizedType) (this.getClass()
				.getGenericSuperclass())).getActualTypeArguments()[0];
	}

	public T getDetail(PK id) {
		try {
			return (T) this.getHibernateTemplate().get(this.tClass, id);
		} catch (RuntimeException re) {
			log.error("find by named query failed", re);
			throw re;
		}

	}

	@SuppressWarnings("unchecked")
	public List<T> getListAll() {
		try {
			String queryString = "from " + this.tClass.getName();
			return super.getHibernateTemplate().find(queryString);
		} catch (RuntimeException re) {
			log.error("find by named query failed", re);
			throw re;
		}
	}

	@SuppressWarnings("unchecked")
	public List<T> getListAll(PageinationEntity page) {
		try {
			DetachedCriteria criteria = DetachedCriteria.forClass(this.tClass);
			return super.getHibernateTemplate().findByCriteria(criteria,
					page.getStart(), page.getLimit());
		} catch (RuntimeException re) {
			log.error("find by named query failed", re);
			throw re;
		}
	}

	@SuppressWarnings("unchecked")
	public List<T> getListByExample(T exampleInstance) {
		try {
			return super.getHibernateTemplate().findByExample(exampleInstance);
		} catch (RuntimeException re) {
			log.error("find by example failed", re);
			throw re;
		}

	}

	@SuppressWarnings("unchecked")
	public List<T> getListByExample(T exampleInstance, PageinationEntity page) {
		try {
			if (page != null)
				return super.getHibernateTemplate().findByExample(
						exampleInstance, page.getStart(), page.getLimit());
			else
				return this.getListByExample(exampleInstance);
		} catch (RuntimeException re) {
			log.error("find by example failed", re);
			throw re;
		}

	}

	@SuppressWarnings("unchecked")
	public List<T> getListByNamedQuery(EnumSystemQueryNameSet queryName) {
		try {
			return super.getHibernateTemplate().findByNamedQuery(
					queryName.getValue());
		} catch (RuntimeException re) {
			log.error("find by named query failed", re);
			throw re;
		}

	}

	@SuppressWarnings("unchecked")
	public List<T> getListByNamedQueryAndNamedParam(
			EnumSystemQueryNameSet queryName, String paramName, Object value) {
		try {
			return super.getHibernateTemplate().findByNamedQueryAndNamedParam(
					queryName.getValue(), paramName, value);
		} catch (RuntimeException re) {
			log.error("find by named query failed", re);
			throw re;
		}

	}

	@SuppressWarnings("unchecked")
	public List<T> getListByNamedQueryAndNamedParams(
			EnumSystemQueryNameSet queryName, String[] paramNames,
			Object[] values) {
		log.debug("finding " + this.tClass + " instance with queryName: "
				+ queryName + ", parameters: " + paramNames + ", values: "
				+ values);
		try {
			return super.getHibernateTemplate().findByNamedQueryAndNamedParam(
					queryName.getValue(), paramNames, values);
		} catch (RuntimeException re) {
			log.error("find by named query failed", re);
			throw re;
		}
	}

	@SuppressWarnings("unchecked")
	public List<T> getListByProperty(String propertyName, Object value) {
		log.debug("finding " + this.tClass + " instance with property: "
				+ propertyName + ", value: " + value);
		try {
			String queryString = "from " + this.tClass.getName()
					+ " as model where model." + propertyName + "= ?";
			return getHibernateTemplate().find(queryString, value);
		} catch (RuntimeException re) {
			log.error("find by property name failed", re);
			throw re;
		}
	}

	public T merge(T detachedInstance) {
		log.debug("merging " + detachedInstance.getClass() + " instance");
		try {
			T result = (T) getHibernateTemplate().merge(detachedInstance);
			log.debug("merge successful");
			return result;
		} catch (RuntimeException re) {
			log.error("merge failed", re);
			throw re;
		}
	}

	public void remove(T persistentInstance) {
		log.debug("removing " + persistentInstance.getClass() + " instance");
		try {
			getHibernateTemplate().delete(persistentInstance);
			log.debug("remove successful");
		} catch (RuntimeException re) {
			log.error("remove failed", re);
			throw re;
		}
	}

	public void removeAll(Collection<T> persistentInstances) {
		log.debug("removing all " + persistentInstances.getClass()
				+ " instance");
		try {
			getHibernateTemplate().deleteAll(persistentInstances);
			log.debug("remove successful");
		} catch (RuntimeException re) {
			log.error("remove failed", re);
			throw re;
		}
	}

	public void save(T transientInstance) {
		log.debug("saving " + transientInstance.getClass() + " instance");
		try {
			getHibernateTemplate().save(transientInstance);
			log.debug("save successful");
		} catch (RuntimeException re) {
			log.error("save failed", re);
			throw re;
		}
	}

	public void saveOrUpdate(T instance) {
		log.debug("saving or updating instance");
		try {
			getHibernateTemplate().saveOrUpdate(instance);
			log.debug("saving or updating successful");
		} catch (RuntimeException re) {
			log.error("saving or updating failed", re);
			throw re;
		}
	}

	public void saveOrUpdateAll(Collection<T> instanceList) {
		log.debug("saving or updating all instances");
		try {
			getHibernateTemplate().saveOrUpdateAll(instanceList);
			log.debug("saving or updating all successful");
		} catch (RuntimeException re) {
			log.error("saving or updating all failed", re);
			throw re;
		}
	}

	public void update(T persistentInstance) {
		log.debug("updating " + persistentInstance.getClass() + " instance");
		try {
			getHibernateTemplate().update(persistentInstance);
			log.debug("update successful");
		} catch (RuntimeException re) {
			log.error("update failed", re);
			throw re;
		}
	}

	@SuppressWarnings("unchecked")
	protected List<T> getListByHql(String hql) {
		return getHibernateTemplate().find(hql);
	}
}
